#include "CManagerTag.h"
#include <iostream>
CManagerTag::CManagerTag(IObservadorTag* tagsManager){
	this->tagsManager = tagsManager;
	this->tagId = 0;
}

CManagerTag::~CManagerTag(){
	if(!this->tagFile.is_open()){
		this->guardarTag();
		this->tagFile.close();
	}
}

bool CManagerTag::crearTag(DBFrecuencias::TagId id){
	if(this->tagFile.is_open()){
		this->guardarTag();
		this->tagFile.close();
	}
	std::stringstream ss;
	std::string file;
	ss << id;
	ss >> file;
	file =DB_TAG + file + ".dat";
	this->tagFile.open(file.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
	this->tagId = id;
	this->tagFile.close();
	return true;
}

/**
 * Este metodo se llama si en el adm del archivo, se intenta agregar una frecuencia
 * y esa frecuencia no esta en el registro
 * 
 */
void CManagerTag::insertarPalabra(DBFrecuencias::TagId tag, DBFrecuencias::Palabra palabra){
	if(this->chequearEstado(tag)){
		this->listaPalabras.insert(palabra);
	}
}
	
/**
 * Este metodo se llama, si se decrementa la frecuencia de una palabra lo suficiente como
 * para que sea 0
 */
void CManagerTag::eliminarPalabra(DBFrecuencias::TagId tag, DBFrecuencias::Palabra palabra){
	if(this->chequearEstado(tag)){
		DBFrecuencias::ListaPalabras::iterator it = this->listaPalabras.find(palabra);
		if(it != this->listaPalabras.end()){
			if((*it)==(*(this->iterador))){
				// si el it interno esta apuntando al mismo nodo, lo paso al prox
				this->iterador++;
			}
			this->listaPalabras.erase(it);
		}
	}
}

bool CManagerTag::eof(){
	bool eof = (this->iterador == this->listaPalabras.end());
	return eof;	
}
	
bool CManagerTag::abrirTag(DBFrecuencias::TagId tag){
	return this->chequearEstado(tag);
}
	
DBFrecuencias::Palabra CManagerTag::leerPalabra(){
	DBFrecuencias::Palabra id = *(this->iterador);
	this->iterador++;
	return id;
}

bool CManagerTag::chequearEstado(DBFrecuencias::TagId tag){
	std::stringstream ss;
	std::string file;
	ss << tag;
	ss >> file;
	file =DB_TAG + file + ".dat";
	if((this->tagId == tag)&&(this->tagFile.is_open())){
		//esta abierto y cargado en memoria
		this->tagFile.seekg(0,std::ios::beg);
		this->iterador = this->listaPalabras.begin();
		return true;
	} else {
		//el tag no estaba en memoria
		if(this->tagId != tag){
			if(this->tagFile.is_open()){
				//habia otro tag abierto, asi que hay que bajarlo a disco
				this->guardarTag();
				this->tagFile.close();
			}
			this->tagId = tag;
		}
		if(this->tagId == tag){
			if(!this->tagFile.is_open()){
				this->tagFile.open(file.c_str(),std::ios::out | std::ios::binary | std::ios::in);
			}
			//se carga el tag en memoria
			this->cargarTag();
		}

	}
	this->tagFile.seekg(0,std::ios::beg);
	return this->tagFile.is_open();
}

void CManagerTag::eliminarTag(DBFrecuencias::TagId tag){
	this->dbFrecuencias->eliminarTag(tag);
	std::stringstream ss;
	std::string file;
	ss << tag;
	ss >> file;
	file =DB_TAG + file + ".dat";
	if((this->tagFile.is_open())&&(this->tagId==tag)){
		this->tagFile.close();
	}
	unlink(file.c_str());
}

void CManagerTag::incrementarNumeroPalabras(DBFrecuencias::TagId tag,DBFrecuencias::Frecuencia frec){
	this->tagsManager->incrementarNumeroPalabras(tag,frec);
}

void CManagerTag::decrementarNumeroPalabras(DBFrecuencias::TagId tag, DBFrecuencias::Frecuencia frec){
	this->tagsManager->decrementarNumeroPalabras(tag,frec);
}

void CManagerTag::cargarTag(){
	this->tagFile.seekg(0,std::ios::beg);
	this->listaPalabras.clear();
	while((!this->tagFile.eof())&&(this->tagFile.peek()!=std::ios::traits_type::eof())){
		DBFrecuencias::LongitudPalabra longitud;
		std::string id;
		this->tagFile.read(reinterpret_cast<char*>(&longitud),sizeof(DBFrecuencias::LongitudPalabra));
		char* buffer = new char[longitud+1];
		this->tagFile.read(reinterpret_cast<char*>(buffer),longitud);
		buffer[longitud]='\0';
		id.assign(buffer);
		delete[] buffer;
		this->listaPalabras.insert(id);
	}
	this->tagFile.clear();
	this->iterador = this->listaPalabras.begin();
}
	
void CManagerTag::guardarTag(){
	this->tagFile.clear();
	this->tagFile.seekp(0,std::ios::beg);
	this->iterador = this->listaPalabras.begin();
	std::string file;
	std::stringstream ss;
	ss << this->tagId;
	ss >> file;
	file =DB_TAG + file + ".dat";
	DBFrecuencias::Offset tamanio = 0;
	for( ;this->iterador != this->listaPalabras.end() ; this->iterador++){
		std::string id = *(this->iterador);
		DBFrecuencias::LongitudPalabra longitud = id.size();
		this->tagFile.write(reinterpret_cast<const char*>(&longitud),sizeof(DBFrecuencias::LongitudPalabra));
		this->tagFile.write(reinterpret_cast<const char*>(id.c_str()),longitud);
		tamanio += sizeof(DBFrecuencias::LongitudPalabra) + longitud;
	}
	this->tagFile.close();
	truncate(file.c_str(), tamanio);
}
